package com.gx.core.shiro.realm;

import com.gx.base.CurrentUser;
import com.gx.domain.SysMenu;
import com.gx.domain.SysRole;
import com.gx.domain.SysUser;
import com.gx.service.api.SysMenuService;
import com.gx.service.api.SysRoleService;
import com.gx.service.api.SysUserService;
import com.gx.utils.bean.BeanUtilsEx;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 认证
 */
public class AuthRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private SysUserService sysUserService;

    @Autowired
    @Lazy
    private SysRoleService sysRoleService;

    @Autowired
    @Lazy
    private SysMenuService sysMenuService;

    /**
     * 授权(验证权限时调用)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        CurrentUser currentUser = (CurrentUser) principals.getPrimaryPrincipal();
        SysUser sysUser = sysUserService.queryObject(currentUser.getUserId());

        List<String> permsList = null;
        Set<String> rolesSet = null;

        //系统管理员，拥有最高权限(可以增加判断同时userId的前缀为admin)
        if ("1".equals(sysUser.getSuperAdmin()) || "user001".equals(sysUser.getUsername())) {
            // 赋予所有角色
            List<SysRole> sysRoles = sysRoleService.queryAll();
//            List<Long> c1 = sysRoles.stream().map(SysRole::getId).collect(Collectors.toList());
//            Map<String, Long> c2 = sysRoles.stream().collect(Collectors.toMap(sysRole -> sysRole.getId().toString(), SysRole::getId));
            rolesSet = sysRoles.stream().map(sysRole -> sysRole.getId().toString()).collect(Collectors.toSet());

            // 赋予所有菜单权限
            List<SysMenu> sysMenus = sysMenuService.queryAll();
            permsList = sysMenus.stream().map(SysMenu::getPermissions).collect(Collectors.toList());
        } else {
            permsList = sysUserService.queryAllPermissions(sysUser.getUserId()); // 写死，实际应该根据人员编号查询对应权限，待实现
        }

        //用户权限列表
        Set<String> permsSet = new HashSet<String>();
        for (String perms : permsList) {
            if (StringUtils.isBlank(perms)) {
                continue;
            }
            permsSet.addAll(Arrays.asList(perms.trim().split(",")));
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        info.setRoles(rolesSet);
        return info;
    }

    /**
     * 认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());

        //查询用户信息
        SysUser sysUser = sysUserService.queryByUserName(username);

        //账号不存在
        if (sysUser == null) {
            throw new UnknownAccountException("账号或密码不正确");
        }

        //密码错误
        if (!password.equals(sysUser.getPassword())) {
            throw new IncorrectCredentialsException("账号或密码不正确");
        }

        //账号锁定
        if (sysUser.getStatus() == null || sysUser.getStatus() == 0) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }

        CurrentUser currentUser = new CurrentUser();
        BeanUtilsEx.copyProperties(currentUser, sysUser);
        currentUser.setPassword(null);

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currentUser, password, getName());
//        ByteSource byteSource = ByteSource.Util.bytes(currentUser.getUserId());
//        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currentUser, password, byteSource, getName());
        return info;
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo() {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

}
